<?php

/**
 * @author Thibaut Cromphaut, Gaïtano Boeraeve, Mathias Helin, Dimitry Dierickx
 * @copyright  Copyright (c) 2011 Artevelde University College Ghent 
 */

class Application_Model_MessageMapper extends Ahs_Model_Mapper
{
    public function __construct(array $options = null)
    {
        parent::__construct($options);
        $this->DbTableName = 'Application_Model_DbTable_Messages';
        $this->PropertiesMap = array
        (
            "Id"            => "message_id",
            "UserToId"      => "users_user_to",
            "UserFromId"    => "users_user_from",
            "SendDate"      => "message_senddate",
            "Subject"       => "message_subject",
            "Content"       => "message_content",
            "ParentId"      => "message_parent_id",
            "IsReadBy"      => "message_isread_by",
            "IsDeletedFor"  => "message_isdeleted_for",
            "DeletedDate"   => "message_deleteddate",
        );
    }
    
    /**
     * Get all parent messages, including deleted ones (For admins only!)
     * 
     * @return Array(Application_Model_Message)
     */
    public function fetchAll()
    {
        $table = $this->getDbTable();
        $select = $table->select();
        $select->where(''.$this->getColumn('ParentId').' = 0')
               ->order(''.$this->getColumn('SendDate').' DESC');
        $rows = $table->fetchAll($select);
        return $this->_toMessages($rows);
    }
    
    /**
     * Get a message by its ID
     * 
     * @param integer $id
     * @return Application_Model_Message
     */
    public function fetchById($id)
    {
        $row = $this->getDbTable()->fetchRow(array(''.$this->getColumn('Id').' = ?' => $id));
        return $this->_toMessage($row);
    }
    
    /**
     * Get all parent messages for a given user
     * 
     * @param integer $user_id
     * @return Array(Application_Model_Message) 
     */
    public function fetchByUserId($user_id)
    {
        $table = $this->getDbTable();
        $select = $table->select();
        $select->where(
                    '('.$this->getColumn('UserToId').' = :user_id OR '.$this->getColumn('UserFromId').' = :user_id)'
                        . ' AND '
                    . $this->getColumn('ParentId').' = 0'
                        . ' AND '
                    . 'FIND_IN_SET(:user_id, '.$this->getColumn('IsDeletedFor').') = 0'
                        . ' AND '
                    . ''.$this->getColumn('DeletedDate').' IS NULL'
                )
               ->bind(array(':user_id' => $user_id))
               ->order(''.$this->getColumn('SendDate').' DESC');
        $rows = $table->fetchAll($select);
        return $this->_toMessages($rows);
    }
    
    /**
     * Get all messages (including the parent) for a parent message id
     * 
     * @param integer $parent_id
     * @return Array(Application_Model_Message) 
     */
    public function fetchByParentId($parent_id)
    {
        $table = $this->getDbTable();
        $select = $table->select();
        $select->where(
                    '('.$this->getColumn('Id').' = :id OR '.$this->getColumn('ParentId').' = :id)'
                        . ' AND '
                    . $this->getColumn('DeletedDate').' IS NULL'
                )
               ->bind(array(':id' => $parent_id))
               ->order(''.$this->getColumn('SendDate').' ASC');
        $rows = $table->fetchAll($select);
        return $this->_toMessages($rows);
    }
    
    /**
     * Get's the number of unread messages for the given user.
     * 
     * @param string $user_id
     * @return integer 
     */
    public function fetchUnreadMessagesCountForUser($user_id)
    {
        $table  = $this->getDbTable();
        $select = $table->select()
                  ->from(
                          $table,
                          array($this->getColumn('Id')))
                  ->where(
                          '('.$this->getColumn('UserToId').' = :user_id OR '.$this->getColumn('UserFromId').' = :user_id)'
                            . ' AND '
                        . 'FIND_IN_SET(:user_id, '.$this->getColumn('IsDeletedFor').') = 0'
                            . ' AND '
                        . ''.$this->getColumn('DeletedDate').' IS NULL'
                            . ' AND '
                        . 'FIND_IN_SET(:user_id, '.$this->getColumn('IsReadBy').') = 0'
                    )
                  ->bind(array(':user_id' => $user_id));
        $rows  = $this->getDbTable()->fetchAll($select);
        
        return count($rows);
    }
    
    /**
     * Get's the number of unread messages for the logged in user for a parent message.
     * 
     * @param string $parent_id
     * @return integer 
     */
    public function fetchUnreadMessagesCountByParentId($parent_id)
    {
        $user_id    = $this->getLoggedInUserId();
        $table      = $this->getDbTable();
        $select     = $table->select()
                      ->from(
                              $table,
                              array($this->getColumn('Id')))
                      ->where(
                              '('.$this->getColumn('Id').' = :parent_id OR '.$this->getColumn('ParentId').' = :parent_id)'
                                . ' AND '
                            . 'FIND_IN_SET(:user_id, '.$this->getColumn('IsDeletedFor').') = 0'
                                . ' AND '
                            . ''.$this->getColumn('DeletedDate').' IS NULL'
                                . ' AND '
                            . 'FIND_IN_SET(:user_id, '.$this->getColumn('IsReadBy').') = 0'
                        )
                      ->bind(array(
                          ':parent_id'  => $parent_id,
                          ':user_id'    => $user_id,
                      ));
        $rows  = $this->getDbTable()->fetchAll($select);
        
        return count($rows);
    }

    /**
     * Save a message
     *
     * @param Application_Model_Course $message
     */
    public function save(Application_Model_Message $message)
    {    
        // Set message ID
        $message_id    = $message->Id;
        
        // We then set our table values
        // This function will only return the non-NULL values
        $data = $this->_getTableValues($message, array("Id"));
        
        // We want to insert the message, if it's an update, we shall throw an exception
        if (null === $message_id)
        {
            $message_id = $this->getDbTable()->insert($data);
        }
        else
        {
            throw new Exception(get_class($this).'->save() -> You cannot update a message!');
        }
        
        return $message_id;
    }
    
    public function markAsRead($parent_id, $user_ids)
    {
        if(null != $parent_id && is_array($user_ids))
        {
            // Remove duplicate values
            $user_ids   = array_unique($user_ids);
            // Set data
            $data[$this->getColumn('IsReadBy')] = implode(",", $user_ids);
            // Where
            $where  = $this->getDbTable()->getAdapter()->quoteInto(''.$this->getColumn('ParentId').' = ? OR '.$this->getColumn('Id').' = ?', $parent_id);
            // Update
            $this->getDbTable()->update($data, $where);
        }
        else
            throw new Exception(get_class($this).'->markAsRead() -> Invalid arguments!');
    }
    
    /**
     * Message delete
     *
     * @param integer $id
     */
    public function delete($id, $user_ids)
    {   
        if(null != $id && is_array($user_ids))
        {
            $data[$this->getColumn('IsDeletedFor')] = implode(",", $user_ids);
            $this->getDbTable()->update($data, array(''.$this->getColumn('Id').' = ?' => $id));
        }
        else
        {
            throw new Exception(get_class($this).'->delete() -> Invalid arguments!');
        }
    }
    
    public function deleteByAdmin($id)
    {
        if(null != $id)
        {
            // Set data
            $data[$this->getColumn('DeletedDate')] = new Zend_Db_Expr('NOW()');
            // Where
            $where  = $this->getDbTable()->getAdapter()->quoteInto(''.$this->getColumn('ParentId').' = ? OR '.$this->getColumn('Id').' = ?', $id);
            // Update
            $this->getDbTable()->update($data, $where);
        }
        else
        {
            throw new Exception(get_class($this).'->deleteByAdmin() -> Invalid arguments!');
        }
    }
    
    /**
     * @param Zend_Db_Table_Row_Abstract $row
     * @return Application_Model_Comment 
     */
    private function _toMessage(Zend_Db_Table_Row_Abstract $row = null)
    {
        // Create a new message object
        $message = new Application_Model_Message();
        
        // Only go on if we actually have a row
        if($row)
        {
            // We have a propertiesmap, let's try to map it back to an object
            foreach($this->PropertiesMap as $key=>$column)
            {
                if(isset($row[$column]))
                    $message->$key      = $row[$column];
            }
        }

        return $message;
    }

    /**
     * @param Zend_Db_Table_Rowset_Abstract $rows
     * @return array
     */
    private function _toMessages(Zend_Db_Table_Rowset_Abstract $rows = null)
    {
        $messages = array();

        if ($rows) {
            foreach ($rows as $row) {
                $messages[] = $this->_toMessage($row);
            }
        }        
        return $messages;
    }

}